package org.common.utils.event;
import com.esotericsoftware.reflectasm.MethodAccess;
import org.common.utils.event.annotation.EventMethod;
import org.common.utils.event.exception.EventEasyException;
import org.common.utils.event.exception.EventEasyInvokeException;
import org.common.utils.event.factory.DefaultEventFactory;
import org.common.utils.event.factory.EventFactory;
import org.common.utils.thread.ThreadExecutor;
import org.common.utils.tool.ClassTool;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;

/**
 * 事件
 * @author zhouzhibing
 * @date 2025/2/24
 */
public class EventEasy {

    private static final EventFactory DEFAULT_EVENT_FACTORY = new DefaultEventFactory();

    /**
     * 调用事件的函数列表<事件类型，事件对象列表>
     */
    private final Map<Class<?> , List<EventObject>> methodMap = new ConcurrentHashMap<>();

    /**
     * 异常处理器
     */
    private final EventFactory eventFactory;

    /**
     * 名称
     */
    private final String name;

    /**
     * 默认异常执行器
     */
    private volatile ThreadExecutor executor;

    public EventEasy(String name , String packageString) {
        this(name , packageString , DEFAULT_EVENT_FACTORY);
    }

    public EventEasy(String name , String packageString , EventFactory eventFactory) {
        if(eventFactory == null)
            throw new EventEasyException("EventEasy eventFactory == null , packageString = " + packageString);
        this.name = name;
        this.eventFactory = eventFactory;
        init(packageString);
    }

    /**
     * 初始化方法，扫描指定包路径下的所有类，筛选出符合条件的类和方法，并进行相关处理
     * @param packageString 要扫描的包路径字符串
     */
    private void init(String packageString) {
        Class<?> currentClass = null;
        Method currentMethod = null;
        try {
            Set<Class<?>> classSet = ClassTool.getAllClass(packageString);
            for (Class<?> instanceClass : classSet) {
                currentClass = instanceClass;
                int modifiers = instanceClass.getModifiers();
                //是抽象类、接口
                if(Modifier.isAbstract(modifiers) || Modifier.isInterface(modifiers))
                    continue;

                Object instance = null;
                MethodAccess methodAccess = null;
                Method[] methods = instanceClass.getDeclaredMethods();

                for (Method instanceMethod : methods) {
                    currentMethod = instanceMethod;

                    //没有标记事件函数
                    EventMethod annotation = instanceMethod.getAnnotation(EventMethod.class);
                    if (annotation == null)
                        continue;

                    //不是public权限
                    int methodModifiers = instanceMethod.getModifiers();
                    if (!Modifier.isPublic(methodModifiers)) {
                        throw new EventEasyException("event method not public modifiers , instanceMethod = " + instanceMethod.getName());
                    }

                    //没有参数
                    int parameterCount = instanceMethod.getParameterCount();
                    if (parameterCount == 0) {
                        throw new EventEasyException("event method not parameter , instanceMethod = " + instanceMethod.getName());
                    }

                    //初始实例
                    if (instance == null) {
                        instance = eventFactory.newInstance(instanceClass);
                        if (instance == null)
                            throw new EventEasyException("init.newInstance instance == null , instanceClass = " + instanceClass);
                    }

                    //初始化函数访问
                    if (methodAccess == null) {
                        methodAccess = MethodAccess.get(instanceClass);
                        if (methodAccess == null)
                            throw new EventEasyException("init.MethodAccess.get methodAccess == null , instanceClass = " + instanceClass);
                    }

                    Class<?> firstParameterType = instanceMethod.getParameterTypes()[0];
                    List<EventObject> eventObjectList = methodMap.computeIfAbsent(firstParameterType, (k) -> new ArrayList<>());
                    int methodIndex = methodAccess.getIndex(currentMethod.getName(), currentMethod.getParameterTypes());
                    eventObjectList.add(new EventObject(instanceClass, instanceMethod, instance, methodAccess, methodIndex));
                }
            }
        } catch (Exception e) {
            String message = currentClass + "#" + currentMethod;
            eventFactory.exceptionHandler(new EventEasyException(message , e));
        }

        if(methodMap.isEmpty())
            throw new EventEasyException("init.methodMap is empty , packageString = " + packageString);

    }

    /**
     * 触发指定事件
     * 找到对应事件类型的处理对象列表，并依次调用其处理方法
     * @param event 事件对象
     */
    public void trigger(Object event) {
        doInvoke(event , null);
    }

    /**
     * 异步触发事件
     * @param event 事件对象，包含事件相关数据
     * @param executor 线程池，用于异步执行事件处理逻辑
     */
    public void triggerAsync(Object event , Executor executor) {
        doInvoke(event , executor);
    }

    /**
     * 异步触发事件 , 默认采用ForkJoinPool.commonPool()中的执行器
     * @param event 事件对象，包含事件相关数据
     */
    public void triggerAsync(Object event) {
        doInvoke(event , getExecutor());
    }

    /**
     * 执行与给定事件相关的方法
     * @param event 触发的事件对象
     * @param executor 用于执行事件处理方法的执行器，如果为null，则直接执行
     * 此方法首先根据事件对象的类获取相应的方法列表如果找不到任何方法，或者方法列表为空，
     * 则抛出异常接下来，根据事件类生成一个调用字符串然后，根据传入的执行器是否为null来决定
     * 是直接执行事件处理方法还是通过执行器来执行这些方法
     */
    private void doInvoke(Object event, Executor executor) {
        Class<?> eventClass = event.getClass();
        List<EventObject> eventObjectList = methodMap.get(eventClass);
        if (eventObjectList == null) {
            throw new EventEasyException("No event found for class: " + eventClass.getName());
        }
        if (eventObjectList.isEmpty()) {
            throw new EventEasyException("Event list is empty for class: " + eventClass.getName());
        }

        if (executor == null) {
            // 依次调用事件处理方法
            for (EventObject eventObject : eventObjectList) {
                handleInvocation(eventClass, eventObject, event);
            }
        } else {
            for (EventObject eventObject : eventObjectList) {
                executor.execute(() -> handleInvocation(eventClass, eventObject, event));
            }
        }
    }

    /**
     * 处理事件调用
     * @param eventClass 事件类型
     * @param eventObject 要调用的事件对象
     * @param event 事件参数
     * 此方法尝试调用给定的事件对象如果调用过程中发生异常，
     * 则创建一个自定义的EventEasyInvokeException并处理该异常
     */
    private void handleInvocation(Class<?> eventClass , EventObject eventObject, Object event) {
        try {
            eventObject.invoke(event);
        } catch (Exception e) {
            eventFactory.exceptionHandler(new EventEasyInvokeException(eventObject.getEventAddress() , eventClass , e));
        }
    }

    /**
     * 获取线程执行器
     * @return 线程执行器
     */
    private ThreadExecutor getExecutor() {
        if(executor == null) {
            synchronized (this) {
                if(executor == null) {
                    executor = new ThreadExecutor(name + "#EventEasy.executor");
                }
            }
        }
        return executor;
    }
}
